<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="description" content="新版个人所得税计算">
    <meta name="keywords" content="个税,个税计算器,2022个税计算器,个人所得税计算,所得税计算"/>
    <title>个税计算器</title>
    <script crossorigin="anonymous"  src="./vue.min.js"></script>
    <style>

        :root {
            --bg-color: #ffffff;
            --hover-color: #cdcdcd;
            --number-color: #0a99ec;
            --number-color-table: #666666;
            --th-bg-color: #666666;
            --point-color: red;
        }

        body {
            background: var(--bg-color);
        }

        #container {
            padding: 10px;
        }

        #container h2 {
            text-align: center;
        }

        .header {
            font-size: 14px;
            font-weight: bold;
        }

        table {
            border-collapse: collapse;
            border-spacing: 0;
            text-align: center;
            background: var(--bg-color);
        }

        td input[type='number'] {
            width: 80px;
            min-width: 80px;
            border: none;
            padding: 5px;
            margin: 0;
            text-align: center;
            color: var(--number-color);
            background: var(--bg-color);
        }


        .table {
            margin: 10px 0;
            min-width: 1024px;
            width: 100%;
            color: var(--number-color-table);
            background: var(--bg-color);
        }

        .table tr {
            transition: all .3s;
            -webkit-transition: all .3s
        }

        .table th {
            text-align: left;
            font-weight: 400
        }

        .table tbody tr:hover, .table thead tr, .table[lay-even] tr:nth-child(even) {
            background-color: var(--hover-color);
        }

        .table td, .table th {
            border-width: 1px;
            border-style: solid;
            border-color: var(--th-bg-color);
            position: relative;
            min-height: 20px;
            line-height: 20px;
            padding: 5px;
            font-size: 14px;
        }

        .form-input {
            width: 90% !important;
        }

        .point {
            color: var(--point-color);
        }

        * {margin:0;padding:0;}  
        html, body {height: 100%;} 
        #container {min-height: 90%;} 
        #main {overflow:auto; }  /* 必须使⽤和footer相同的⾼度 */ 


    


        .header {
            color: #022a42;
        }

        #footer {
            position: relative;  
            clear:both; 
            margin: 0px auto;
            background-color: #fff;
            border-top: 1px solid #eee;
            padding: 23px 0 12px;
            width: 100%;
        }
        #footer a{
            font-size: 12px;
            color: #999;
            text-decoration: underline;
        
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-align: center;
            -ms-flex-align: center;
            align-items: center;
            -webkit-box-pack: center;
            -ms-flex-pack: center;
            justify-content: center;
            padding-top: 6px;
            height: 16px;
            line-height: 16px;
        }
        #footer i{
            display: inline-block;
            width: 14px;
            height: 16px;
            margin-right: 6px;
            background: url(./img/icon_police.png) 0 0 no-repeat;  
        }
    </style>
</head>
<body>
<div id="container" >
   <div class="header">
        <h2>{{year}}个人所得税计算器</h2>
    </div> 
    <div>
        <table class="table">
            <tr class="header">
                <td>税前月收入</td>
                <td>个税起征点</td>
                <td>专项附加扣除</td>
                <td>依法确定的其他扣除</td>
                <td>社保</td>
                <td>公积金</td>
                <td>年收入</td>
                <td>年缴社保</td>
                <td>年缴公积金</td>
                <td>年缴社保公积金</td>
                <td>年累计纳税额</td>
                <td>税后年收入</td>
                <td>税后年收入+提取全年公积金(*2)</td>
            </tr>
            <tr class="header">
                <td><input type="number" class="form-input" v-model.number="ysr" @change="verification"></td>
                <td><input type="number" class="form-input" v-model.number="deductData.gsqzd"></td>
                <td><input type="number" class="form-input" v-model.number="deductData.zxfjkc"></td>
                <td><input type="number" class="form-input" v-model.number="deductData.qtkc"></td>
                <td><input type="number" class="form-input" v-model.number="deductData.sb"></td>
                <td><input type="number" class="form-input" v-model.number="deductData.gjj"></td>
                <td class="point">{{nsr}}</td>
                <td class="point">{{nsb}}</td>
                <td class="point">{{ngjj}}</td>
                <td class="point">{{nsbgjj}}</td>
                <td class="point">{{nljnse}}</td>
                <td class="point">{{sjnsr}}</td>
                <td class="point">{{sjnsrgjj}}</td>
            </tr>
        </table>
    </div>
    <table class="table">
        <tr class="header">
            <td width="60">月份</td>
            <td>月收入</td>
            <td>免税收入</td>
            <td>减除费用</td>
            <td>专项扣除(社保)</td>
            <td>专项扣除(公积金)</td>
            <td>专项附加扣除</td>
            <td>依法确定的其他扣除</td>
            <td>累计收入</td>
            <td>累计免税收入</td>
            <td>累计减除费用</td>
            <td>累计专项扣除</td>
            <td>累计专项附加扣除</td>
            <td>累计依法确定的其他扣除</td>
            <td>累计预扣预缴应纳税所得额</td>
            <td>累计应纳税额</td>
            <td>适用税率</td>
            <td>应预缴的税款</td>
            <td>税后收入</td>
        </tr>
        <tr v-for="item in monthData">
            <td>{{item.num}}月</td>
            <td><input type="number" v-model.number="item.ysr"></td><!--每月收入-->
            <td><input type="number" v-model.number="item.mssr"></td><!--每月免税收入-->
            <td><input type="number" v-model.number="item.jcfy"></td><!--每月减除费用-->
            <td><input type="number" v-model.number="item.zxkc_sb"></td><!--每月专项扣除(社保)-->
            <td><input type="number" v-model.number="item.zxkc_gjj"></td><!--每月专项扣除(公积金)-->
            <td><input type="number" v-model.number="item.zxfjkc"></td><!--每月专项附加扣除-->
            <td><input type="number" v-model.number="item.qtkc"></td><!--每月依法确定的其他扣除-->
            <td>{{toFixed(item.ljsr)}}</td><!--累计收入-->
            <td>{{toFixed(item.ljmssr)}}</td><!--累计免税收入-->
            <td>{{toFixed(item.ljjcfy)}}</td><!--累计减除费用-->
            <td>{{toFixed(item.ljzxkc)}}</td><!--累计专项扣除-->
            <td>{{toFixed(item.ljzxfjkc)}}</td><!--累计专项附加扣除-->
            <td>{{toFixed(item.ljqtkc)}}</td><!--累计依法确定的其他扣除-->
            <td>{{toFixed(item.ljykyjylssd)}}</td><!--累计预扣预缴应纳税所得额-->
            <td>{{toFixed(item.ljylse)}}</td><!--累计应纳税额-->
            <td>{{item.rate}}%</td><!--适用税率-->
            <td>{{toFixed(item.yyjysk)}}</td><!--每月应预缴的税款-->
            <td>{{toFixed(item.yndsr)}}</td><!--每月拿到收入-->
        </tr>
    </table>
</div>


<div id="footer">
    <div style="font-size: 12px; color: #999;">
        <a  href="http://beian.miit.gov.cn" target="_blank"><i></i>湘ICP备19020868号</a>
    </div>    
</div>
</body>
<script>
    let vm = new Vue({
        el: '#container',
        data: {
            year: new Date().getFullYear(),
            //月收入
            ysr: 0,
            levelData: [
                {level: 1, range: 0, rate: 3, kcs: 0, text: '不超过36000元'},
                {level: 2, range: 36000, rate: 10, kcs: 2520, text: '超过36000元至144000元的部分'},
                {level: 3, range: 144000, rate: 20, kcs: 16920, text: '超过144000元至300000元的部分'},
                {level: 4, range: 300000, rate: 25, kcs: 31920, text: '超过300000元至420000元的部分'},
                {level: 5, range: 420000, rate: 30, kcs: 52920, text: '超过420000元至660000元的部分'},
                {level: 6, range: 660000, rate: 35, kcs: 85920, text: '超过660000元至960000元的部分'},
                {level: 7, range: 960000, rate: 45, kcs: 181920, text: '超过960000元的部分'}
            ],
            deductData: {
                //个税起征点
                gsqzd: 0,
                //专项附加扣除
                zxfjkc: 0,
                //依法确定的其他扣除
                qtkc: 0,
                //扣社保
                sb: 0,
                //公积金
                gjj: 0
            },
            monthData: []
        },
        computed: {
            //实际拿到手的年收入
            sjnsr: function () {
                let total = 0;
                this.monthData.forEach(item => total += item.yndsr)
                return this.toFixed(total);
            },
            //实际拿到手的年收入+ 提取全年公积金(*2包括公司部分)
            sjnsrgjj: function () {
                let total = 0;
                this.monthData.forEach(item => total += (item.yndsr + (item.zxkc_gjj * 2)))
                return this.toFixed(total);
            },
            //年累计纳税额
            nljnse: function () {
                let total = 0;
                this.monthData.forEach(item => total += item.yyjysk)
                return this.toFixed(total);
            },
            //年收入
            nsr: function () {
                let total = 0;
                this.monthData.forEach(item => total += item.ysr)
                return this.toFixed(total);
            },
            //年缴社保公积金
            nsbgjj: function () {
                let total = 0;
                this.monthData.forEach(item => total += item.zxkc_sb + item.zxkc_gjj)
                return this.toFixed(total);
            },
            //年缴社保
            nsb: function () {
                let total = 0;
                this.monthData.forEach(item => total += item.zxkc_sb)
                return this.toFixed(total);
            },
            //年缴公积金
            ngjj: function () {
                let total = 0;
                this.monthData.forEach(item => total += item.zxkc_gjj)
                return this.toFixed(total);
            }
        },
        watch: {
            ysr: function (newVal, oldVal) {
				console.log("ysrnewVal:"+newVal);
				console.log("ysroldVal:"+oldVal);
				
				let jishu = 31014;
				jishu = jishu > newVal ? newVal : jishu;
				let yanglao = jishu * 0.08;
				let yiliao = jishu * 0.02;
				let shiye = jishu * 0.005;
				let gongjijin = jishu * 0.07;
				
				let shebao = yanglao + yiliao + shiye;
				this.deductData.sb = shebao;
				this.deductData.gjj = gongjijin;
				
                this.monthData.forEach(item => item.ysr = newVal);
                this.calculate();
            },
            'deductData.gsqzd': {
                handler(newVal, oldVal) {
                    this.monthData.forEach(item => item.jcfy = newVal);
                    this.calculate();
                },
                immediate: true
            },
            'deductData.sb': {
                handler(newVal, oldVal) {
                    this.monthData.forEach(item => item.zxkc_sb = newVal);
					
                    this.calculate();
                },
                immediate: true
            },
            'deductData.gjj': {
                handler(newVal, oldVal) {
                    this.monthData.forEach(item => item.zxkc_gjj = newVal);
                    this.calculate();
                },
                immediate: true
            },
            'deductData.zxfjkc': {
                handler(newVal, oldVal) {
                    this.monthData.forEach(item => item.zxfjkc = newVal);
                    this.calculate();
                },
                immediate: true
            },
            'deductData.qtkc': {
                handler(newVal, oldVal) {
                    this.monthData.forEach(item => item.qtkc = newVal);
                    this.calculate();
                },
                immediate: true
            },
            monthData: {
                handler(newVal, oldVal) {
                    if (!(newVal.ysr != oldVal.ysr || newVal.mssr != oldVal.mssr)) {
                        this.calculate();
                    }
                },
                deep: true
            }
        },
        methods: {
            verification: function () {
                if (this.ysr <= 5000) {
                    this.ysr = 10000;

                    this.createMonthData();
                    alert("您尚未达到起征点！无需计算！");
                }
            },
            createMonthData: function () {
                this.monthData = [];
                let month = 12;
                for (let i = 1; i <= month; i++) {
                    this.monthData.push({
                        num: i,
                        ysr: 0,
                        mssr: 0,
                        jcfy: 0,
                        zxkc_sb: 0,
                        zxkc_gjj: 0,
                        zxfjkc: 0,
                        qtkc: 0,
                        ljsr: 0,
                        ljmssr: 0,
                        ljjcfy: 0,
                        ljzxkc: 0,
                        ljzxfjkc: 0,
                        ljqtkc: 0,
                        ljykyjylssd: 0,
                        rate: 0,
                        ljylse: 0,
                        yyjysk: 0,
                        yndsr: 0
                    });
                }
            },
            calculate: function () {
                this.calculateAccumulative();
            },
            toFixed: function (val) {
                return val.toFixed(2);
            },
            calculateAccumulative: function () {
                this.monthData.forEach((item, i) => {
                    let preData = undefined;
                    if (i > 0) {
                        preData = this.monthData[i - 1];
                        item.ljsr = preData.ljsr + item.ysr;
                        item.ljmssr = preData.ljmssr + item.mssr;
                        item.ljjcfy = preData.ljjcfy + item.jcfy;
                        item.ljzxkc = preData.ljzxkc + item.zxkc_sb + item.zxkc_gjj;
                        item.ljzxfjkc = preData.ljzxfjkc + item.zxfjkc;
                        item.ljqtkc = preData.ljqtkc + item.qtkc;
                    } else {
                        item.ljsr = item.ysr;
                        item.ljmssr = item.mssr;
                        item.ljjcfy = item.jcfy;
                        item.ljzxkc = item.zxkc_sb + item.zxkc_gjj;
                        item.ljzxfjkc = item.zxfjkc;
                        item.ljqtkc = item.qtkc;
                    }
                    //累计预扣预缴应纳税所得额
                    item.ljykyjylssd = item.ljsr - item.ljmssr - item.ljjcfy - item.ljzxkc - item.ljzxfjkc - item.ljqtkc;
                    let level = this.getLevelData(item.ljykyjylssd);
                    item.rate = level.rate;
                    // 累计应纳税额=累计预扣预缴应纳税所得额*税率-速算扣除数
                    item.ljylse = (item.ljykyjylssd * (level.rate / 100)) - level.kcs;
                    //每月应预缴的税款
                    if (preData != undefined) {
                        item.yyjysk = item.ljylse - preData.ljylse;
                    } else {
                        item.yyjysk = item.ljylse;
                    }
                    item.yndsr = item.ysr - (item.zxkc_sb + item.zxkc_gjj) - item.yyjysk;
                });
            },
            //取得计算税率   累计预扣预缴应纳税所得额
            getLevelData: function (ljykyjylssd) {
                let data = undefined;
                //按顺序比大小
                this.levelData.forEach(item => {
                    if (ljykyjylssd >= item.range) {
                        data = item;
                    }
                });
                return data;
            },
        },
        created: function () {
            this.createMonthData();
            this.ysr = 10000;
            this.deductData.gsqzd = 5000;
            this.deductData.sb = 1000;
            this.deductData.gjj = 200;
            this.deductData.zxfjkc = 0;
            this.deductData.qtkc = 0;
            this.calculate();
        }
    });
</script>
</html>
